#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>

#include <linux/regmap.h>
#include <linux/sysfs.h>

typedef struct virt_regulator_plat_data_s
{
	struct regmap *regmap;
	struct regulator_init_data *init_data;
}virt_regulator_plat_data_t;

struct virt_regulator_dev{
	struct regmap *regmap;
	struct regulator_dev *dev;
	
};


#define VIRT_VOLTAGE_SEL_REG	0x01
#define		VIRT_VOLTAGE_VSEL_MASK		0x00F0 //bit[7:4]

#define VIRT_VOLRTAGE_ENABLE_REG	0x02
#define 	VIRT_VOLTAGE_ENABLE_MASK	0x0010 //bit4





static struct regulator_ops virt_regulator_ops = {
	.list_voltage = regulator_list_voltage_linear,
	.map_voltage = regulator_map_voltage_linear,
	.get_voltage_sel = regulator_get_voltage_sel_regmap,
	.set_voltage_sel = regulator_set_voltage_sel_regmap,
	.enable 	= regulator_enable_regmap,
	.disable	= regulator_disable_regmap,
	.is_enabled = regulator_is_enabled_regmap,

};

static struct regulator_desc virt_regulator_desc = {
	.name = "regulator-virt0630",
	.type = REGULATOR_VOLTAGE,
	.ops = &virt_regulator_ops,
	.vsel_reg = VIRT_VOLTAGE_SEL_REG,
	.vsel_mask = VIRT_VOLTAGE_VSEL_MASK,
	.enable_reg = VIRT_VOLRTAGE_ENABLE_REG,
	.enable_mask = VIRT_VOLTAGE_ENABLE_MASK,
	.min_uV = 2000000,
	.uV_step = 200000,
	.n_voltages = 8,
	.owner = THIS_MODULE,
};

static int virt_regulator_platform_probe(struct platform_device *platform_dev)
{
	struct virt_regulator_dev *virt_regulator_ptr;
	virt_regulator_plat_data_t *plat_datap = platform_dev->dev.platform_data;
	struct regulator_config config;

	memset(&config, 0, sizeof(struct regulator_config));
	
	printk("%s:%d\n", __FUNCTION__, __LINE__);
	virt_regulator_ptr = devm_kzalloc(&platform_dev->dev, sizeof(*virt_regulator_ptr), GFP_KERNEL);
	if (!virt_regulator_ptr)
		return -ENOMEM;

	virt_regulator_ptr->regmap = plat_datap->regmap;
	if(plat_datap->regmap == NULL || plat_datap->init_data == NULL)
	{
		printk("%s:%d\n", __FUNCTION__, __LINE__);
		return -EINVAL;
	}

	config.dev = &platform_dev->dev;	
	config.init_data = plat_datap->init_data;
	config.regmap = plat_datap->regmap;
	config.driver_data = virt_regulator_ptr;

	
	virt_regulator_ptr->dev = regulator_register(&virt_regulator_desc, &config);
	if (IS_ERR(virt_regulator_ptr->dev)) 
	{
		printk("failed to register regulator %s\n",virt_regulator_desc.name);
		return PTR_ERR(virt_regulator_ptr->dev);
	}
	
	platform_set_drvdata(platform_dev, virt_regulator_ptr);
	return 0;
}


static int virt_regulator_platform_remove(struct platform_device *platform_dev)
{
	struct virt_regulator_dev *rdev = platform_get_drvdata(platform_dev);

	regulator_unregister(rdev->dev);

	platform_set_drvdata(platform_dev, NULL);
	printk("%s:%d\n", __FUNCTION__, __LINE__);
	return 0;
}

static struct platform_driver virt_regulator_platform_driver = {
	.driver = {
		.name = "virt_regulator_dev",
		.owner = THIS_MODULE,
	},
	.probe = virt_regulator_platform_probe,
	.remove = virt_regulator_platform_remove,
};


static int __init virt_regulator_dev_init(void)
{
	int ret = 0;

	ret = platform_driver_register(&virt_regulator_platform_driver);

	return ret;
}

static void __exit virt_regulator_dev_exit(void)
{
 	   printk("%s:%d\n", __FUNCTION__, __LINE__);

	platform_driver_unregister(&virt_regulator_platform_driver);
}



module_init(virt_regulator_dev_init);
module_exit(virt_regulator_dev_exit);
MODULE_DESCRIPTION("Virtual Regulator Controller Platform Device Drivers");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jerry_chg");
